
#include "StdAfx.h"
#include "aplExListCtrl.h"
#include <aplAggr.h>

int CaplExListCtrl::sm_sbSize = ::GetSystemMetrics(SM_CYHSCROLL);

/////////////////////////////////////////////////////////////////////////////
// CaplExListCtrl

CaplExListCtrl::CaplExListCtrl()
{
	WNDCLASS wc;
	wc.cbClsExtra = NULL;
	wc.cbWndExtra = NULL;
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.hCursor = LoadCursor (NULL, IDC_ARROW);
	wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
	wc.hInstance = AfxGetResourceHandle();
	wc.lpszMenuName = NULL;
	wc.lpszClassName = _T("CaplExListCtrl");
	wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
	wc.lpfnWndProc = ::DefWindowProc;
	AfxRegisterClass(&wc);

	m_list = new CaplExListCtrlContent;
	m_header = new CHRArray;

	m_pWarningMessageWnd = NULL;

	m_nHeadersId = 10;
	m_selind = -2;
	m_curSel = NULL;
	m_ptLastSort.x = m_ptLastSort.y = 0;
	m_pIL = NULL;
	m_bUnselItemDel = false;
	
	
	m_UserDefRH = CaplExListItem::m_nDefRowHeight-::GetSystemMetrics(SM_CYBORDER);
	m_RH = m_UserDefRH;
	m_iconsRH = 0;
	m_iconWidth = 0;
	m_pg = true;
	if(CaplExListItem::m_gridPen.m_hObject == NULL)
		CaplExListItem::m_gridPen.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_BTNFACE));

	if(CaplExListItem::m_selColor == 0)
		CaplExListItem::m_selColor = ::GetSysColor(COLOR_HIGHLIGHT);
}

void CaplExListCtrl::OnDestroy() 
{
	DeleteAllItems();
	int co = m_header->GetSize();
	for(int i=co-1; i>=0; i--) 
		DeleteRow(i);

	CWnd::OnDestroy();
}

CaplExListCtrl::~CaplExListCtrl()
{
	for(int i=m_header->GetSize()-1; i>=0; i--)
		delete m_header->GetAt(i);

	if(m_list) delete m_list;
	m_list = NULL;
	if(m_header) delete m_header;
	m_header = NULL;
}


BEGIN_MESSAGE_MAP(CaplExListCtrl, CWnd)
	//{{AFX_MSG_MAP(CaplExListCtrl)
	ON_WM_PAINT()
	ON_WM_SIZE()
	ON_WM_ERASEBKGND()
	ON_NOTIFY(HDN_ENDTRACK, 10, OnItemchangedList1)
	ON_WM_VSCROLL()
	ON_WM_HSCROLL()
	ON_WM_LBUTTONDOWN()
	ON_NOTIFY(HDN_ITEMCLICK, 10, OnItemclickList1)
	ON_WM_LBUTTONDBLCLK()
	ON_WM_DESTROY()
	ON_WM_MOUSEWHEEL()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

//////////////////////////////////////////////////////////////////////////
// CaplExListCtrl functions

// Header functions
void CaplExListCtrl::GetContentRect(RECT &re)
{
	GetClientRect(&re);
	re.top += m_header->GetSize() * CaplExHeaderRow::m_HH + m_border;
	re.left += m_border;
	if(m_sbHorz.IsWindowVisible())
		re.bottom -= (m_border) + sm_sbSize;
	else
		re.bottom -= m_border;
	if(m_sbVert.IsWindowVisible())
		re.right -= (m_border) + sm_sbSize;
	else
		re.right -= m_border;
}

void CaplExListCtrl::UpdateContent()
{
	CRect re;
	GetContentRect(re);
	RedrawWindow(&re);
}

int CaplExListCtrl::AddRow(int index)
{
	if (m_list->m_items.GetCount() > 0)
	{
		return -1;
	}
	if((index < 0) || (index > m_header->GetSize()))
		index = m_header->GetSize();    // добавляем в конец

	CRect re,pre;
	int i;
//	int dy = -re.Height();

	GetWindowRect(&pre);

	for (i=index; i<m_header->GetSize(); i++)
	{
		m_header->GetAt(i)->m_hc.GetWindowRect(&re);
		re.OffsetRect(-pre.left, CaplExHeaderRow::m_HH - pre.top);
		m_header->GetAt(i)->m_hc.MoveWindow(&re);
	}

	CaplExHeaderRow *hr = new CaplExHeaderRow(this, index, m_nHeadersId, m_fo, m_border>0);
	if(index == 0)
		m_list->m_header = hr;
	if((index < m_header->GetSize()))
	{
		hr->m_subHeader = m_header->GetAt(index);
	}

	if(index>0)
		m_header->GetAt(index-1)->m_subHeader = hr;

	m_header->InsertAt(index, hr);

	VisibleScrolls();

	return index;
}

int CaplExListCtrl::AddColumn(int rowIndex, int colIndex, LPCTSTR text, int w, int nFormat, aplEditTypes mode, CStringArray *pStrs)
{
	if((rowIndex < 0) || (rowIndex >= m_header->GetSize()))
		return -1;
	
	CaplExHeaderRow *hr = m_header->GetAt(rowIndex);

	EndEdit(true,true);
	if((colIndex > hr->m_hc.GetItemCount()) || (colIndex < 0))
		colIndex = hr->m_hc.GetItemCount();

	UINT hdFmt = ((nFormat == LVCFMT_LEFT) ? HDF_LEFT : ((nFormat == LVCFMT_CENTER) ? HDF_CENTER : HDF_RIGHT));

	hr->InsertItem(colIndex, (LPTSTR)text, w, hdFmt, mode, pStrs);

	// add cell in all items
	if(hr->m_countItems>0)
		m_list->EnumLevelLists(rowIndex, CaplExListCtrlContent::AddCells, colIndex, 1);

	VisibleScrolls();
	UpdateContent();

	return colIndex;
}



bool CaplExListCtrl::DeleteRow(int index)
{
	int i;
	if (m_list->m_items.GetCount() > 0)
	{
		return 0;
	}
	if((index < 0) || (index >= m_header->GetSize()))
		return 0;

	CRect re,pre;
	GetWindowRect(&pre);
	m_header->GetAt(index)->m_hc.GetWindowRect(&re);
	int dy = -re.Height();
	for (i=index+1; i<m_header->GetSize(); i++)
	{
		m_header->GetAt(i)->m_hc.GetWindowRect(&re);
		re.OffsetRect(-pre.left, dy-pre.top);
		m_header->GetAt(i)->m_hc.MoveWindow(&re);
	}

	if(index > 0)
		m_header->GetAt(index-1)->m_subHeader = m_header->GetAt(index)->m_subHeader;

	else
	{
		m_list->m_header = m_list->m_header->m_subHeader;
	}
	CaplExHeaderRow *hr = m_header->GetAt(index);
//	hr->m_hc.DestroyWindow();

	delete hr;

	m_header->RemoveAt(index,1);

	VisibleScrolls();

	return true;
}

bool CaplExListCtrl::DeleteColumn(int row, int col)
{
	if((row < 0) || (row >= m_header->GetSize()))
		return false;
	
	CaplExHeaderRow *hr = m_header->GetAt(row);

	if((col < 0) || (col >= hr->m_hc.GetItemCount()))
		return false;
	EndEdit(true,true);
	if(hr->m_countItems>0)
		m_list->EnumLevelLists(row, CaplExListCtrlContent::DelCell, col, 0);
	hr->DeleteItem(col);
	VisibleScrolls();
	UpdateContent();
	return true;
}

bool CaplExListCtrl::SplitColumn(int row, int col, int count)
{
	if((row < 0) || (col < 0) || (count<2) || (row >= m_header->GetSize())) return false;
	CaplExHeaderRow *hd = m_header->GetAt(row);
	if(col >= hd->m_hc.GetItemCount()) return false;
	EndEdit(true,true);
	bool ret = hd->Split(col, count);
	if(ret && (hd->m_countItems > 0))
	{
		m_list->EnumLevelLists(row, CaplExListCtrlContent::AddCells, col+1, count);
		VisibleScrolls();
		UpdateContent();
	}

	return ret;
}

bool CaplExListCtrl::SetColumnText(int row, int col, LPCTSTR lpszTitle)
{
	if((row < 0) || (row >= m_header->GetSize()))
		return false;
	
	CaplExHeaderRow *hr = m_header->GetAt(row);

	if((col < 0) || (col >= hr->m_hc.GetItemCount()))
		return false;

	int tl;
	HDITEM item;
	item.mask = HDI_TEXT;
	if(lpszTitle != NULL)
	{
		for(tl = 0; lpszTitle[tl] != 0; tl++);
		item.cchTextMax = tl+1;
		item.pszText = (LPTSTR)lpszTitle;
	}
	else
	{
		item.pszText = _T("");
		item.cchTextMax = 1;
	}
	
	hr->m_hc.SetItem(col, &item);

	return true;
}

void CaplExListCtrl::HeaderLayout()
{
	int w, mw = 0;
	int i, mi = 0, co = m_header->GetSize();
	CaplExHeaderRow *hr;
	for (i=0; i<co; i++)
	{
		hr = m_header->GetAt(i);
		w = hr->Width();
		if(w > mw)
		{
			mw = w;
			mi = i;
		}
	}
	for(i=0; i<co; i++)
	{
		if(i != mi)
		{
			hr = m_header->GetAt(i);
			hr->SetWidth(mw);
		}
	}
}

void CaplExListCtrl::SetRowHeight(int rh)
{
	if(rh<8) return;
	EndEdit(true,true);
	m_UserDefRH = rh;
	if(rh < m_iconsRH) rh = m_iconsRH;
	if(rh == m_RH) return;
	m_RH = rh;
	VisibleScrolls();
	UpdateContent();
}

bool CaplExListCtrl::SetItemImage(HLISTITEM item, int imageIndex)
{
	if(!item) return false;
	CaplExListItem *li = CLIList::GetItemByHLI(item);
	if(!li) return false;
	li->m_imageIndex = imageIndex;

	if(VisibleItem(item))
		UpdateContent();

	return true;
}

bool CaplExListCtrl::SetImageList(CImageList *pImageList, bool bSetRowHeightByIcons)
{
	if(m_pIL == pImageList) return false;
	EndEdit(true,true);
	m_iconsRH = 0;
	m_iconWidth = 0;
	if(!pImageList)
	{
		m_pIL = NULL;
		m_RH = m_UserDefRH;
		VisibleScrolls();
		UpdateContent();
		return true;
	}

	int dh, dw, i, co = pImageList->GetImageCount();

	IMAGEINFO ii;
	for (i=0; i<co; i++)
	{
		pImageList->GetImageInfo(i, &ii);
		dh = ii.rcImage.bottom - ii.rcImage.top;
		dw = ii.rcImage.right - ii.rcImage.left;
		if(dh > m_iconsRH)   m_iconsRH   = dh;
		if(dw > m_iconWidth) m_iconWidth = dw;
	}

	m_iconsRH +=2;
	m_pIL = pImageList;

	if(m_iconsRH > m_RH) m_RH = m_iconsRH;
	if(bSetRowHeightByIcons)
	{
		m_UserDefRH = m_iconsRH;
		m_RH = m_iconsRH;
	}

	VisibleScrolls();
	UpdateContent();

	return true;	
}

HLISTITEM CaplExListCtrl::InsertItem(int index, LPCTSTR text, int imageIndex)
{
	return InsertSubItem(NULL, index, text, imageIndex);
}

HLISTITEM CaplExListCtrl::InsertSubItem(HLISTITEM item, int index, LPCTSTR text, int imageIndex)
{
	if(m_header->GetSize()<1) return NULL;
	EndEdit(true);
	CaplExListItem *it = NULL;
	CaplExListCtrlContent *lst = NULL;
	if(item) 
	{
		it = CLIList::GetItemByHLI(item);
		if(it->m_header->m_subHeader == NULL) return NULL;
		lst = it->m_subItems;
		if(lst==0) 
		{
			lst = new CaplExListCtrlContent;
			it->m_subItems = lst;
			lst->m_header = it->m_header->m_subHeader;
			lst->m_parentItem = item;
			lst->m_absCount = 0;
			lst->m_parentList = it->m_thisList;
		}
	}
	else
		lst = m_list;

	POSITION ret = NULL;

	CaplExListItem *ni = new CaplExListItem(it);
	ni->m_imageIndex = imageIndex;
	
	if((index < 0) || (index >= lst->m_items.GetCount()))  //добавляем в конец
	{
		ret = lst->Add(ni);
		lst->SetItemText(ret, 0, text);
	//	if(text) ni->m_cells.SetAt(0, text);
	}
	else
	{
		POSITION pi = lst->GetAt(index);
		ret = lst->Insert(ni, pi);
		lst->SetItemText(ret, 0, text);
	//	if(text) ni->m_cells.SetAt(0, text);
	}

	VisibleScrolls();
	UpdateContent();

	return ret;
}

HLISTITEM CaplExListCtrl::GetParentItem(HLISTITEM item)
{
	if(!item) return NULL;
	CaplExListItem *it = CLIList::GetItemByHLI(item);
	if(!it) return NULL;
	return it->m_thisList->m_parentItem;
}

CaplExListCtrlContent *CaplExListCtrl::GetAllChilds(HLISTITEM item)
{
	if(m_header->GetSize()<1) return 0;
	CaplExListItem *it = NULL;
	if(item) 
	{
		it = CLIList::GetItemByHLI(item);
		return ((!it->m_header->m_subHeader) ? NULL : it->m_subItems);
	}
	else return m_list;
}

int CaplExListCtrl::GetSubItemsCount(HLISTITEM item)
{
	CaplExListCtrlContent *lst = GetAllChilds(item);
	return (lst ? lst->m_items.GetCount() : 0);
}

HLISTITEM CaplExListCtrl::GetSubItem(HLISTITEM item, int index)
{
	CaplExListCtrlContent *lst = GetAllChilds(item);
	return (lst ? lst->GetAt(index) : 0);
}

HLISTITEM CaplExListCtrl::GetFirstSubItem(HLISTITEM item)
{
	CaplExListCtrlContent *lst = GetAllChilds(item);
	return (lst ? lst->m_items.GetHeadPosition() : NULL);
}

HLISTITEM CaplExListCtrl::GetLastSubItem(HLISTITEM item)
{
	CaplExListCtrlContent *lst = GetAllChilds(item);
	return (lst ? lst->m_items.GetTailPosition() : NULL);
}

HLISTITEM CaplExListCtrl::GetNextItem(HLISTITEM item, bool bNext)
{
	if((m_header->GetSize()<1)||(!item)) return NULL;
	return CLIList::GetNextHLI(item, bNext);
}

HLISTITEM CaplExListCtrl::GetTrueNextItem(HLISTITEM item, bool bNext /* = true */)
{
	if((m_header->GetSize()<1)||(!item)) return NULL;
	HLISTITEM ret;
	if(bNext)
	{
		ret = GetFirstSubItem(item);
		if(ret) return ret;
		while((ret = GetNextItem(item, true)) == NULL)
		{
			item = GetParentItem(item); 
			if(!item) return NULL;
		}
		return ret;
	}
	else
	{
		ret = GetNextItem(item, false);
		if(!ret) return GetParentItem(item);
		item = GetLastSubItem(ret);
		while(item)
		{
			ret = item;
			item = GetLastSubItem(item);
		}
		return ret;
	}
}


CString CaplExListCtrl::GetItemText(HLISTITEM item, int col)
{
	if((m_header->GetSize()<1)||(!item)) return _T("");
	CaplExListItem *it = CLIList::GetItemByHLI(item);
	CaplExListCtrlContent *lst = it->m_thisList;
	return lst->GetItemText(item, col);
}

bool CaplExListCtrl::SetItemText(HLISTITEM item, int col, LPCTSTR lpszText)
{
	if((m_header->GetSize()<1)||(!item)) return false;
	CaplExListItem *it = CLIList::GetItemByHLI(item);
	CaplExListCtrlContent *lst = it->m_thisList;
	bool re = lst->SetItemText(item, col, lpszText);
	if(re && VisibleItem(item))
		UpdateContent();
	return re;
}

bool CaplExListCtrl::SetItemData(HLISTITEM item, DWORD dwData)
{
	if(!item) return false;
	CaplExListItem *it = CLIList::GetItemByHLI(item);
	if(!it) return false;
	it->m_data = dwData;
	return true;
}

DWORD CaplExListCtrl::GetItemData(HLISTITEM item)
{
	if(!item) return 0;
	CaplExListItem *it = CLIList::GetItemByHLI(item);
	if(!it) return 0;
	return it->m_data;
}

bool CaplExListCtrl::DeleteItem(int index)
{
	return true;
}

bool CaplExListCtrl::DeleteItem(HLISTITEM item)
{
	if(!item) return false;
	CaplExListItem *it = CLIList::GetItemByHLI(item);
	if(!it) return false;
	CaplExListCtrlContent *lst = it->m_thisList;
	if(!lst) return false;
	if(lst->m_items.GetCount()<1) return false;
	EndEdit(true,true);
	if(m_curSel == item) 
	{
		m_bUnselItemDel = true;
		SelectItem(NULL);
	}
	lst->Delete(item);
	VisibleScrolls();
	UpdateContent();
	
	return true;
}

bool CaplExListCtrl::DeleteAllItems()
{
	EndEdit(false);

	m_list->DeleteAll();
	for (int i=0; i<m_header->GetSize(); i++)
	{
		CaplExHeaderRow *hr = m_header->GetAt(i);
		hr->m_countItems = 0;
	}
	VisibleScrolls();
	m_curSel = NULL;
	UpdateContent();
	return true;
}

bool CaplExListCtrl::EnsureVisible(HLISTITEM item)
{
	if(!item) return false;
	if(!m_sbVert.IsWindowVisible()) return true;

	EndEdit(true,true);

	CaplExListCtrlContent *lst = CLIList::GetItemByHLI(item)->m_thisList;
	int ii = m_selind;
	if(ii < 0)
		ii = lst->GetAbsIndex(item);

	if(ii<0) return false;

	SCROLLINFO si;
	m_sbVert.GetScrollInfo(&si, SIF_PAGE | SIF_POS |SIF_RANGE);
	
	if((ii >= si.nPos) && (ii < si.nPos + (int)si.nPage))	return true;
/*
	if(ii < si.nPos)
		ii = si.nPos;
	if(ii >= si.nPos + (int)si.nPage)
		ii = si.nPos + (int)si.nPage - 1;
/*/
//	if(ii > si.nMax - si.nPos + 1)
//		ii = si.nMax - si.nPos + 1;
//*/

	DoScroll(SB_THUMBTRACK, ii, &m_sbVert, false);

	return true;
}


bool CaplExListCtrl::SendMessageAboutSCH(UINT code, HLISTITEM item)
{
	CWnd *pWnd = GetParent();
	if(pWnd && ::IsWindow(pWnd->m_hWnd))
	{
		NMEXLISTVIEW nmListView;
		memset(&nmListView, 0, sizeof(NMEXLISTVIEW));
		nmListView.hdr.idFrom = GetDlgCtrlID();
		nmListView.hdr.code = code;
		nmListView.hdr.hwndFrom = m_hWnd;
		nmListView.mode = aplNone;
		nmListView.item = item;
		nmListView.subItem = 0;
		nmListView.editWnd = NULL;
		int nmRet = pWnd->SendMessage(WM_NOTIFY, (WPARAM)GetDlgCtrlID(), (LPARAM)&nmListView);
		if((!m_bUnselItemDel) && (nmRet != 0) && (code == APL_EXLC_SEL_CHANGING_MESSAGE))
			return false;
	}
	return true;
}

bool CaplExListCtrl::SelectItem(HLISTITEM item)
{
	if (item == m_curSel) 
	{
		m_bUnselItemDel = false;
		return true;
	}
	if(!m_bUnselItemDel)
		if(!SendMessageAboutSCH(APL_EXLC_SEL_CHANGING_MESSAGE, item)) return false;

	m_bUnselItemDel = false;

	CRect re;
	GetClientRect(&re);
	re.top+=m_border + m_header->GetSize() * CaplExHeaderRow::m_HH;
	
	if (item == NULL)
	{
		m_curSel = NULL;
		m_selind = -2;
		RedrawWindow(&re);
		SendMessageAboutSCH(APL_EXLC_SEL_CHANGED_MESSAGE, item);
		return true;
	}

	CaplExListCtrlContent *lst = CLIList::GetItemByHLI(item)->m_thisList;
	int ii = m_selind;
	if(ii < 0)
		ii = lst->GetAbsIndex(item);

	m_selind = -2;
	if(ii<0) 
	{
		return false;
	}

	m_curSel = item;
	
	if(!m_sbVert.IsWindowVisible())
	{
		RedrawWindow(&re);
		SendMessageAboutSCH(APL_EXLC_SEL_CHANGED_MESSAGE, item);
		return true;
	}

	SCROLLINFO si;
	m_sbVert.GetScrollInfo(&si, SIF_PAGE | SIF_POS);
	
	if((ii >= si.nPos) && (ii <= si.nPos + (int)si.nPage))
		RedrawWindow(&re);

	SendMessageAboutSCH(APL_EXLC_SEL_CHANGED_MESSAGE, item);
	
	return true;
}

HLISTITEM CaplExListCtrl::GetSelectedItem()
{
	return m_curSel;
}

bool CaplExListCtrl::MoveUp(HLISTITEM item)
{
	if(!item) return false;
	CaplExListCtrlContent *lst = CLIList::GetItemByHLI(item)->m_thisList;
	if(lst->MoveUp(item))
	{
		UpdateContent();
		return true;
	}
	else
		return false;
}

bool CaplExListCtrl::MoveDown(HLISTITEM item)
{
	if(!item) return false;
	CaplExListCtrlContent *lst = CLIList::GetItemByHLI(item)->m_thisList;
	if(lst->MoveDown(item))
	{
		UpdateContent();
		return true;
	}
	else
		return false;
}

bool CaplExListCtrl::SetItemEditMode(HLISTITEM item, int subItem, aplEditTypes mode, CStringArray *pStrs, bool bSharedStrs)
{
	if(m_header->GetSize()<1) return 0;
	if(!item) return false;
	CaplExListItem *it = CLIList::GetItemByHLI(item);
	if(!it) return false;
	EndEdit(true,true);
	int bS = bSharedStrs?1:0;
	it->SetMode(subItem, mode, pStrs, bS);
	return true;
}

bool CaplExListCtrl::Sort(int row, int col)
{
	if((row<0) || (col<0) || (row >= m_header->GetSize())) return false;
	CaplExHeaderRow *hr = m_header->GetAt(row);
	if(col >= hr->m_hc.GetItemCount()) return false;
	EndEdit(true,true);
	m_list->EnumLevelLists(row, CaplExListCtrlContent::Sort, col, hr->GetSortType(col,true));
	m_ptLastSort.y = row;
	m_ptLastSort.x = col;
	UpdateContent();
	return true;
}

bool CaplExListCtrl::ReSort()
{
	return Sort(m_ptLastSort.y, m_ptLastSort.x);
}

void CaplExListCtrl::PaintGrid(bool pg)
{
	if(m_pg != pg)
	{
		m_pg = pg;
		EndEdit(true,true);
		UpdateContent();
	}
}

void CaplExListCtrl::SetBorder(bool b)
{
	if(b != (m_border>0))
	{
		EndEdit(true,true);
		if(b) 
		{
			m_border = APLEXLISTCTL_BORDER;
		//	ModifyStyle(0, WS_BORDER);
		}
		else 
		{
			m_border = 0;
		//	ModifyStyle(WS_BORDER, 0);
		}
		UpdateWindow();
	}
}

void CaplExListCtrl::GetContentSize(CSize &sz, bool bWithHeader)
{
	int hco = m_header->GetSize();
	int w=0, wk;
	for (int i=0; i<hco; i++)
	{
		wk = m_header->GetAt(i)->Width();
		if(wk > w) w = wk;
	}
	sz.cx = w;
	if(bWithHeader)
	{
		sz.cy = hco*CaplExHeaderRow::m_HH + m_list->m_absCount * m_RH;
	}
	else
	{
		sz.cy = m_list->m_absCount * m_RH;
	}
}

bool CaplExListCtrl::VisibleScrolls(bool bResize)
{
	CRect re, pre;
	BOOL bV = FALSE, bH = FALSE;
	int w = 0, h = 0;
	GetWindowRect(&re);
	pre = re;
	re.OffsetRect(-re.left, -re.top);
	if(m_border>0)
	{
		re.right -=(m_border<<1);
		re.bottom -= (m_border<<1);
	}
	CSize sz;
	GetContentSize(sz, true);
	if(re.bottom < sz.cy)
	{
		bV = TRUE;
		re.right -= sm_sbSize;
	}
	if(re.right < sz.cx)
	{
		bH = TRUE;
		re.bottom -= sm_sbSize;
	}
	if(re.bottom < sz.cy)
	{
		if(!bV) re.right -= sm_sbSize;
		bV = TRUE;
	}
	re.OffsetRect(m_border,m_border);
	int d = m_header->GetSize() * CaplExHeaderRow::m_HH;
	re.top += d;
	sz.cy -= d;
	CRect re2 = re; //size window

	SCROLLINFO si;
	si.fMask = SIF_RANGE|SIF_PAGE;
	BOOL oldBV = m_sbVert.IsWindowVisible();
	BOOL oldBH = m_sbHorz.IsWindowVisible();
	
	if(bH)
	{
		re = re2;
		re.top = re.bottom;
		re.bottom = re.top + sm_sbSize;
		m_sbHorz.MoveWindow(&re, oldBH);
		si.nMin = 0;
		si.nMax = sz.cx;
		si.nPage = re2.right;
		m_sbHorz.SetScrollInfo(&si, oldBH);
	}
	else
	{
		CRect rect;
		GetWindowRect(&rect);
		for (int i=0; i<m_header->GetSize(); i++)
		{
			m_header->ElementAt(i)->HScroll(0,rect, m_border);
		}
		m_sbHorz.SetScrollPos(0, FALSE);
	}

	if((oldBV != bV)||(bResize))
	{
		
		int h1;
		CaplExHeaderRow *hr;

		for (h1 = 0; h1 < m_header->GetSize(); h1++)
		{
			hr = m_header->GetAt(h1);
			hr->m_hc.GetWindowRect(&re);
			re.right = pre.right - (m_border<<1)+1;
			re.OffsetRect(-pre.left, -pre.top);
			
			
			if(bV) re.right -= sm_sbSize-2;
			
			hr->m_hc.MoveWindow(&re,TRUE);
		}
		
	}

	if(bV)
	{
		re = re2;
		re.left = re.right;
		re.right = re.left+sm_sbSize;
		si.nPage = re.Height() / m_RH;
		re.top -= m_header->GetSize() * CaplExHeaderRow::m_HH;
		si.nMin = 0;
		si.nMax = (sz.cy) / m_RH - 1;
		m_sbVert.SetScrollInfo(&si, oldBV);
		m_sbVert.MoveWindow(&re, oldBV);
	}
	else
		m_sbVert.SetScrollPos(0, FALSE);

	m_sbHorz.ShowScrollBar(bH);
	m_sbVert.ShowScrollBar(bV);
	return false;
}

/////////////////////////////////////////////////////////////////////////////
// CaplExListCtrl message handlers

BOOL CaplExListCtrl::OnEraseBkgnd(CDC* pDC) 
{
	return TRUE;
}

void CaplExListCtrl::OnPaint() 
{
	CRect re, bmpre;
	GetWindowRect(re);
	re.OffsetRect(-re.left, -re.top);
	bmpre = re;
	re.bottom -= m_border;
	re.right  -= m_border;
	re.left   += m_border;
	re.top    += m_border;
	int y0 = CaplExHeaderRow::m_HH * m_header->GetSize();
	re.top += y0;
	CRect re1 = re;

	CPaintDC pdc(this); 
	CDC dc;
	dc.CreateCompatibleDC(&pdc);
	CBitmap bm, *oldBM;
	bm.CreateCompatibleBitmap(&pdc, bmpre.right, bmpre.bottom);
	oldBM = dc.SelectObject(&bm);
	dc.FillSolidRect(&bmpre, RGB(255, 255, 255));

	
	CFont *oldFont = dc.SelectObject(&m_fo);
	BOOL bv = m_sbVert.IsWindowVisible();
	BOOL bh = m_sbHorz.IsWindowVisible();
	int scp = 0;

	if(bv)
	{
		scp = m_sbVert.GetScrollPos();
		re.right -= sm_sbSize;
	}
	if(bh)
	{
		re.left -= (m_sbHorz.GetScrollPos()/*<<3*/);
		re.bottom -= sm_sbSize;
	}

	CRect re2 = re;
	m_list->sm_curSel = m_curSel;
	m_list->Paint(dc, scp, re, m_pg, m_iconWidth, m_pIL);
	dc.SelectObject(oldFont);
	if(bv && bh)
	{
		dc.FillSolidRect(re2.right, re2.bottom-1, sm_sbSize, sm_sbSize+1, GetSysColor(COLOR_BTNFACE));
		dc.SetBkColor(RGB(255, 255, 255));
	}
	if(m_border>0)
	{	
		/*
		HPEN op = (HPEN)dc.SelectObject(::GetStockObject(WHITE_PEN));
		dc.MoveTo(0,re1.bottom);
		dc.LineTo(re.right+sm_sbSize, re.bottom);
		dc.LineTo(re.right+sm_sbSize, 0);
		dc.SelectObject(op);
		*/
	
		re1.top = re1.left = 0;
		re1.right += 2;
		re1.bottom += 2;
		dc.DrawEdge(&re1, EDGE_SUNKEN, BF_RECT);
	}
	
	pdc.BitBlt(0, 0, bmpre.right, bmpre.bottom, &dc, 0, 0, SRCCOPY);
	dc.SelectObject(oldBM);
	bm.DeleteObject();
	dc.DeleteDC();
}



void CaplExListCtrl::OnSize(UINT nType, int cx, int cy) 
{
	EndEdit(true,true);
	
	CRect re;
	VisibleScrolls(true);
	GetWindowRect(&re);
	re.OffsetRect(-re.left, -re.top);
	RedrawWindow(&re);
//	CWnd::OnSize(nType, cx, cy);
}

void CaplExListCtrl::PreSubclassWindow() 
{
	HWND wnd = m_hWnd;
	m_fo.CreateStockObject(ANSI_VAR_FONT);

	if(!::IsWindow(m_edit_ctrl.m_hWnd))
	{
		m_edit_ctrl.Create(WS_CHILD|ES_AUTOHSCROLL|WS_BORDER, CRect(0,0,1,1), this, 1); //-V525
		m_edit_ctrl.SetFont(&m_fo);
	}

	if(!::IsWindow(m_combo_ctrl.m_hWnd))
	{
		m_combo_ctrl.Create(WS_BORDER|WS_CHILD|CBS_DROPDOWNLIST,CRect(0,0,90,125), this, 2);
		m_combo_ctrl.SetFont(&m_fo);
	}

	if(!::IsWindow(m_date_ctrl.m_hWnd))
	{
		m_date_ctrl.Create(WS_BORDER|WS_CHILD|DTS_SHORTDATEFORMAT, CRect(0,0,0,0), this, 3);
		m_date_ctrl.SetFont(&m_fo);
	}

	if(!::IsWindow(m_time_ctrl.m_hWnd))
	{
		m_time_ctrl.Create(WS_BORDER|WS_CHILD|DTS_TIMEFORMAT, CRect(0,0,0,0), this, 4);
		m_time_ctrl.SetFont(&m_fo);
	}

	if(!::IsWindow(m_ToolTipCtrl.m_hWnd))
	{
		m_ToolTipCtrl.Create(this, TTS_BALLOON|TTS_NOPREFIX|TTS_ALWAYSTIP);
		m_ToolTipCtrl.SetDelayTime(0);
	}

	EnableToolTips();

	this->ModifyStyle(0, WS_CLIPCHILDREN);
	CRect re;
	GetWindowRect(&re);
	re.OffsetRect(-re.left, -re.top);
	m_border = APLEXLISTCTL_BORDER;

	re.right-=m_border+1;
	re.left = re.right - sm_sbSize;
	re.top+=m_border;
	re.bottom -= m_border+1+sm_sbSize;

	SCROLLINFO si;
	si.fMask = SIF_PAGE|SIF_RANGE|SIF_POS;
	m_sbVert.Create(SBS_VERT|WS_CHILD|WS_VISIBLE, re, this, 7);
	
	si.nMin = 0;
	si.nMax = 5;
	si.nPos = 0;
	si.nPage = 1;
	m_sbVert.SetScrollInfo(&si);

	GetWindowRect(&re);
	re.OffsetRect(-re.left, -re.top);

	re.right-=m_border+1   +sm_sbSize;;
	re.left = m_border;
	re.bottom -= m_border+1;
	re.top = re.bottom - sm_sbSize;

	m_sbHorz.Create(SBS_HORZ|WS_CHILD|WS_VISIBLE, re, this, 8);
	
	si.nMin = 0;
	si.nMax = 5;
	si.nPos = 0;
	si.nPage = 1;
	m_sbHorz.SetScrollInfo(&si);

	CWnd::PreSubclassWindow();
}



BOOL CaplExListCtrl::OnCommand(WPARAM wParam, LPARAM lParam) 
{
	return CWnd::OnCommand(wParam, lParam);
}

void CaplExListCtrl::OnItemclickList1(NMHDR* pNMHDR, LRESULT* pResult) 
{
	if(EndEdit(true)) return;
	SetFocus();
	HD_NOTIFY *phdn = (HD_NOTIFY *) pNMHDR;
	int i;
	CaplExHeaderRow *hr = NULL;
	for (i = 0; i<m_header->GetSize(); i++)
	{
		hr = m_header->GetAt(i);
		if(hr->m_hc.m_hWnd == phdn->hdr.hwndFrom)
			break;
	}
	Sort(i, phdn->iItem);
	*pResult = 0;
}

void CaplExListCtrl::OnItemchangedList1(NMHDR* pNMHDR, LRESULT* pResult) 
{
	if(EndEdit(true, true)) return;
	SetFocus();
	HD_NOTIFY *phdn = (HD_NOTIFY *) pNMHDR;
	HWND hw = phdn->hdr.hwndFrom;
	int i;
	CaplExHeaderRow *hr = NULL, *hr1;
	for (i = 0; i<m_header->GetSize(); i++)
	{
		hr = m_header->GetAt(i);
		if(hr->m_hc.m_hWnd == hw)
			break;
	}
	if(hr==NULL) return;

	int le = hr->Width();
	for (i = 0; i<m_header->GetSize(); i++)
	{
		hr1 = m_header->GetAt(i);
		if(hr != hr1) hr1->SetWidth(le);
	}

	VisibleScrolls();
	CRect re;
	GetWindowRect(&re);
	re.OffsetRect(-re.left, -re.top);
	RedrawWindow(&re);
	
	*pResult = 0;
}

BOOL CaplExListCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) 
{
	if(zDelta == 0) return 1;
	if(zDelta < 0)
		DoScroll(SB_LINEDOWN, 0, &m_sbVert, false);
	else
		DoScroll(SB_LINEUP, 0, &m_sbVert, false);
	return 1;
//	return CWnd::OnMouseWheel(nFlags, zDelta, pt);
}

void CaplExListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { DoScroll(nSBCode, nPos, pScrollBar, false); }
void CaplExListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { DoScroll(nSBCode, nPos, pScrollBar, true); }

void CaplExListCtrl::DoScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar, bool bH)
{
	SCROLLINFO si;
	SetFocus();
	if(EndEdit(true)) return;
	pScrollBar->GetScrollInfo(&si);
	int pg = (int)si.nPage;
	int newPos = si.nPos;
	int mp;
	mp = si.nMax - si.nPage+1;
	switch(nSBCode)
	{
	case SB_BOTTOM:
		newPos = si.nMax;
		pScrollBar->SetScrollPos(si.nMax);
		break;
	case SB_ENDSCROLL:

		break;
	case SB_LINEDOWN:
		if(si.nPos < mp) 
		{
			if(bH) {newPos += 8; if(newPos>mp) newPos = mp;}
			else newPos ++;
			pScrollBar->SetScrollPos(newPos);
		}
		break;
	case SB_LINEUP:
		if(si.nPos > si.nMin) 
		{
			if(bH) {newPos -= 8; if(newPos<si.nMin) newPos = si.nMin;}
			else newPos --;
			pScrollBar->SetScrollPos(newPos);
		}
		break;
	case SB_PAGEDOWN:
		if(si.nPos <= mp-pg) newPos += pg;
		else if(si.nPos < mp) newPos = mp;
		else return;
		pScrollBar->SetScrollPos(newPos);
		break;
	case SB_PAGEUP:
		if(si.nPos >= si.nMin+pg) newPos -= pg;
		else if(si.nPos > si.nMin) newPos = si.nMin;
		else return;
		pScrollBar->SetScrollPos(newPos);
		break;
	case SB_THUMBPOSITION:
		break;
	case SB_THUMBTRACK:
		newPos = nPos;
		if(nPos != (UINT)si.nPos) pScrollBar->SetScrollPos(nPos);
		break;
	case SB_TOP:
		newPos = si.nMin;
		pScrollBar->SetScrollPos(si.nMin);
		break;
	}
	if(newPos != si.nPos)
	{
		if(bH)  // скроллируем заголовки
		{
			CRect pre;
			GetWindowRect(&pre);
			for (int i=0; i<m_header->GetSize(); i++)
			{
				m_header->ElementAt(i)->HScroll(newPos, pre, m_border);
			}
		}
		CRect re;
		UpdateContent();
	}
}

int  CaplExListCtrl::ItemByPoint(const CPoint &point, POSITION &pos)
{
	int p = 0;
	if(m_sbVert.IsWindowVisible())
		p = m_sbVert.GetScrollPos();
	CRect re;
	GetContentRect(re);
	if(!re.PtInRect(point)) return -2;
	int spos = p + (point.y - re.top) / m_RH;
	if(spos > m_list->m_absCount)
	{
		pos = NULL;
		return -1;
	}
	CaplExListCtrlContent *lst = m_list;
	POSITION po;
	m_list->GetAbsAt(spos, po, lst);
	pos = po;
	return spos;
}

void CaplExListCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
	POSITION po;
	SetFocus();
	if(EndEdit(true)) return;
	int spos = ItemByPoint(point, po);
	if(spos == -2) return;
	m_selind = spos;
	SelectItem(po);
}

void CaplExListCtrl::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	POSITION po;
	SetFocus();
	if(EndEdit(true)) return;
	int spos = ItemByPoint(point, po);
	if(spos < 0) return;
	int y0 = spos * m_RH + m_header->GetSize() * CaplExHeaderRow::m_HH;
	if(m_sbVert.IsWindowVisible())
		y0 -= m_sbVert.GetScrollPos() * m_RH;
	
	CRect re;
	GetContentRect(re);
	if(y0 > re.bottom - m_RH)
	{
		DoScroll(SB_LINEDOWN, 0, &m_sbVert, false);
		y0 -= m_RH;
	}

	if(m_sbHorz.IsWindowVisible())
		point.x -= m_sbHorz.GetScrollPos();

	StartEdit(y0, po, point.x);
}

LRESULT CaplExListCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
	int yyy = 0;
	if((message == WM_STYLECHANGING) && (wParam == GWL_STYLE))
	{
		STYLESTRUCT *ss = (STYLESTRUCT *)lParam;
		bool bOldSort, bSort;
		bSort = ((ss->styleNew & LVS_NOSORTHEADER)==0);
		bOldSort = ((ss->styleOld & LVS_NOSORTHEADER)==0);
		if(bSort != bOldSort)
		{
			CaplExHeaderRow *hr;
			for(int i=0; i<m_header->GetSize(); i++)
			{
				hr = m_header->GetAt(i);
				hr->SetEnableSort(bSort);
			}
		}
	}
	return CWnd::WindowProc(message, wParam, lParam);
}

bool CaplExListCtrl::StartEdit(int y0, HLISTITEM pos, int x)
{
	if(!pos) return false;
	CaplExListItem *li = CLIList::GetItemByHLI(pos);
	if(!li) return false;

	CRect rect;
	int cell,i;
	if(!li->GetInfo(x, rect, cell)) return false;

	rect.top = y0+1;
	rect.right += m_border-1;
	rect.bottom = y0 + m_RH +m_border;
	if(cell == 0) 
		rect.left += m_iconWidth;
	rect.left += m_border;
	rect.top += m_border;
	if(m_sbHorz.IsWindowVisible())
	{
		int gsp = m_sbHorz.GetScrollPos();
		rect.OffsetRect(-gsp,0);
		if(rect.left<m_border)
		{
			DoScroll(SB_THUMBTRACK, gsp - m_border + rect.left, &m_sbHorz, true);
			rect.OffsetRect(m_border - rect.left,0);
		}
	}
	CaplExListCtrlContent *lst = li->m_thisList;
	CString text = lst->GetItemText(pos, cell);
	CStringArray *pStrs = NULL;
	aplEditTypes mode = li->GetMode(cell, pStrs);
	
	if(mode == aplNone) return false;

	m_ei.m_curEdit = mode;
	m_ei.m_edItem  = pos;
	m_ei.lst = lst;
	m_ei.ncol = cell;

	int minH = 21;

	//начинаем редактировать наш элемент
	switch(mode)
	{
	case aplTextCtrl:
	case aplRealCtrl:
	case aplIntegerCtrl:
	case aplTimeCtrl:
		{
			if(::IsWindow(m_edit_ctrl.m_hWnd))
			{
				m_edit_ctrl.MoveWindow(rect, FALSE);
				m_edit_ctrl.SetWindowText(text);
				m_edit_ctrl.SetSel(0,-1);
				m_edit_ctrl.ShowWindow(SW_SHOW);
				m_edit_ctrl.SetFocus();
				m_ei.m_editWnd = &m_edit_ctrl;
			}
		}
		break;
		
	case aplComboCtrl:
		{
			if(::IsWindow(m_combo_ctrl.m_hWnd))
			{
				m_combo_ctrl.ResetContent();
				m_combo_ctrl.MoveWindow(rect, FALSE);
				m_ei.m_editWnd = &m_combo_ctrl;
				int tfp = -1;
				if(pStrs)
				{
					for (i=0; i<pStrs->GetSize(); i++)
					{
						m_combo_ctrl.AddString(pStrs->ElementAt(i));
						if(pStrs->ElementAt(i) == text) tfp = i;
					}
				}
				if(tfp >= 0)
					m_combo_ctrl.SetCurSel(tfp);
				else
				{
					m_combo_ctrl.InsertString(0, text);
					m_combo_ctrl.SetCurSel(0);
				}
				m_combo_ctrl.ShowWindow(SW_SHOW);
				m_combo_ctrl.SetFocus();
			}
		}
		break;

	case aplDateCtrl:
		if(::IsWindow(m_date_ctrl.m_hWnd))
		{
			if(rect.Height() < minH) rect.bottom = rect.top + minH;
			m_ei.m_editWnd = &m_date_ctrl;
			m_date_ctrl.MoveWindow(rect, FALSE);
			m_date_ctrl.ShowWindow(SW_SHOW);
			m_date_ctrl.SetFocus();
		}
		break;
/*
	case aplTimeCtrl:
		if(::IsWindow(m_time_ctrl.m_hWnd))
		{
			if(rect.Height() < minH) rect.bottom = rect.top + minH;
			m_ei.m_editWnd = &m_time_ctrl;
			m_time_ctrl.MoveWindow(rect, FALSE);
			m_time_ctrl.ShowWindow(SW_SHOW);
			m_time_ctrl.SetFocus();
		}
		break;
*/
	case aplUser:
		{
			CWnd* pWnd = GetParent();
			if(pWnd && ::IsWindow(pWnd->m_hWnd))
			{
				NMEXLISTVIEW nmListView;
				memset(&nmListView, 0, sizeof(NMEXLISTVIEW));
				
				nmListView.hdr.idFrom = GetDlgCtrlID();
				nmListView.hdr.code = APL_LC_START_EDIT_MESSAGE;
				nmListView.hdr.hwndFrom = m_hWnd;

				nmListView.editWnd = NULL;
				nmListView.mode = aplUser;
				nmListView.item = pos;
				nmListView.subItem = cell;
				
				pWnd->SendMessage(WM_NOTIFY, (WPARAM)GetDlgCtrlID(), (LPARAM)&nmListView);
			}
		}
		break;
	
	default:
		break;
	}
	return true;
}

bool CaplExListCtrl::SetErrorMessageText(LPCTSTR lpszText)
{
	m_sErrorText = lpszText;
	
	CString sTitle =  _T("Invalid value");
	CRect r;
	
	switch(m_ei.m_curEdit)
	{
	case aplTextCtrl:
	case aplRealCtrl:
	case aplIntegerCtrl:
	case aplTimeCtrl:
		m_pWarningMessageWnd = &m_edit_ctrl;
		break;
		
	case aplComboCtrl:
		m_pWarningMessageWnd = &m_combo_ctrl;
		break;

	case aplDateCtrl:
		m_pWarningMessageWnd = &m_date_ctrl;
		break;
	default:
		return false;
		break;
	}

	if(GetDllVersion(_T("comctl32.dll"))>=PACKVERSION(5,0) && ::IsWindow(m_ToolTipCtrl.m_hWnd))
	{
		m_pWarningMessageWnd->GetWindowRect(&r);
		
		m_ToolTipCtrl.DelTool(m_pWarningMessageWnd);
		m_ToolTipCtrl.AddTool(m_pWarningMessageWnd, m_sErrorText);
		m_ToolTipCtrl.SendMessage(TTM_SETTITLE, TTI_ERROR, (LPARAM)(LPCTSTR)sTitle);
		
		::SetCursorPos(r.left+2, r.top+2);
	}
	else
	{
		{
			AfxMessageBox(m_sErrorText, MB_OK|MB_ICONSTOP);
			return false;
		}
	}
	
	return true;
}

bool CaplExListCtrl::EndEdit(bool bUpdate, bool bTryUpdate)
{
	if(m_ei.m_curEdit == aplNone) return false;
	if(m_ei.ee)
	{
		if(!bUpdate)
		{
			CaplExListItem *li = CLIList::GetItemByHLI(m_ei.m_edItem);
//			li->m_editInfo = NULL;
			m_ei.NoEdit();
			SetFocus();
			UpdateContent();
		}
		return true;
	}
	m_ei.ee = true;

	CString text, buf, msg;
	CWnd* pWnd = GetParent();
	aplEditTypes em = m_ei.m_curEdit;
	
 	if(pWnd && ::IsWindow(pWnd->m_hWnd) && bUpdate && !bTryUpdate)
	{
		NMEXLISTVIEW nmListView;
		memset(&nmListView, 0, sizeof(NMEXLISTVIEW));
		nmListView.hdr.idFrom = GetDlgCtrlID();
		nmListView.hdr.code = APL_LC_BEFORE_END_EDIT_MESSAGE;
		nmListView.hdr.hwndFrom = m_hWnd;
		
		nmListView.mode = m_ei.m_curEdit;
		nmListView.item = m_ei.m_edItem;
		nmListView.subItem = m_ei.ncol;

		if(m_ei.m_curEdit <= aplIntegerCtrl)
			nmListView.editWnd = &m_edit_ctrl;
		else if(m_ei.m_curEdit == aplComboCtrl)
			nmListView.editWnd = &m_combo_ctrl;
		else
			nmListView.editWnd = NULL;

		int ret = pWnd->SendMessage(WM_NOTIFY, (WPARAM)GetDlgCtrlID(), (LPARAM)&nmListView);
		if(m_ei.m_curEdit == aplNone) 
		{
			SetFocus();
			return false;
		}
		if(ret!=0)
		{
			if(m_ei.m_editWnd) m_ei.m_editWnd->SetFocus();
			else SetFocus();
			m_ei.ee = false;
			return false;
		}
	}

	if(m_ei.m_curEdit == aplNone) return true;
//	CString oldText;
//	if(bUpdate) oldText = GetItemText(m_ei.m_edItem, m_ei.ncol);
	

	if((em == aplIntegerCtrl) || (em == aplTextCtrl) || (em == aplRealCtrl) || (em == aplTimeCtrl))
	{
		if(bUpdate)
		{
			m_edit_ctrl.GetWindowText(text);
			if(em == aplRealCtrl)
			{
				if(!TestCharactValue(text, false, msg, false))
				{
					if(!bTryUpdate)
					{
						m_edit_ctrl.SetFocus();
						SetErrorMessageText(msg);
						m_edit_ctrl.SetFocus();
					}
					else m_ei.NoEdit();
					m_ei.ee = false;
					return true;
				}
			}
			else if(em==aplIntegerCtrl)
			{
				if(!text.IsEmpty() && !IsInteger(text))
				{
					if(!bTryUpdate)
					{
						m_edit_ctrl.SetFocus();
						//SetErrorMessageText( "The field value must be an integer! (Значение поля должно быть целым числом!)");
						SetErrorMessageText( APL_T("Значение поля должно быть целым числом!"));
						m_edit_ctrl.SetFocus();
					}
					else m_ei.NoEdit();
					m_ei.ee = false;
					return true;
				}
			}
			else if(em==aplTimeCtrl)
			{
				if(!TestCharactValue(text, true, msg, false))
				{
					if(!bTryUpdate)
					{
						m_edit_ctrl.SetFocus();
						SetErrorMessageText(msg);
						m_edit_ctrl.SetFocus();
					}
					else m_ei.NoEdit();
					m_ei.ee = false;
					return true;
				}
			}
			SetItemText(m_ei.m_edItem, m_ei.ncol, text);
		}
		m_edit_ctrl.SetSel(0, -1);
	}
	
	else if(em == aplComboCtrl)
	{
		if(bUpdate)
		{
			m_combo_ctrl.GetWindowText(text);
			SetItemText(m_ei.m_edItem, m_ei.ncol, text);
		}
	}

	else if(em == aplDateCtrl)
	{
		CTime time;
		CDateTimeCtrl *dtc = (CDateTimeCtrl *)m_ei.m_editWnd;
		if(GDT_VALID == dtc->GetTime(time))
			dtc->GetWindowText(text);
		else
			text.Empty();
		if(bUpdate)
			SetItemText(m_ei.m_edItem, m_ei.ncol, text);
	}

	m_ei.NoEdit();

	if(pWnd && ::IsWindow(pWnd->m_hWnd) && bUpdate)
	{
		NMEXLISTVIEW nmListView;
		memset(&nmListView, 0, sizeof(NMEXLISTVIEW));
		nmListView.hdr.idFrom = GetDlgCtrlID();
		nmListView.hdr.code = APL_LC_AFTER_END_EDIT_MESSAGE;
		nmListView.hdr.hwndFrom = m_hWnd;
		
		nmListView.mode = m_ei.m_curEdit;
		nmListView.item = m_ei.m_edItem;
		nmListView.subItem = m_ei.ncol;
		nmListView.editWnd = NULL;
		
		pWnd->SendMessage(WM_NOTIFY, (WPARAM)GetDlgCtrlID(), (LPARAM)&nmListView);
	}

	
	SetFocus();
	m_ei.ee = false;

	m_sErrorText.Empty();

	m_pWarningMessageWnd = NULL;

	if(::IsWindow(m_ToolTipCtrl.m_hWnd))
	{
		m_ToolTipCtrl.DelTool(&m_edit_ctrl);
		m_ToolTipCtrl.DelTool(&m_combo_ctrl);
		m_ToolTipCtrl.DelTool(&m_time_ctrl);
	}

	UpdateContent();
	return true;
}

bool CaplExListCtrl::EndEdit(bool bUpdate)
{
	return EndEdit(bUpdate, false);
}

BOOL CaplExListCtrl::PreTranslateMessage(MSG* pMsg) 
{
	if(!m_sErrorText.IsEmpty() && m_pWarningMessageWnd)
		m_ToolTipCtrl.RelayEvent(pMsg);
	
	if(pMsg->message == WM_KEYDOWN)
	{
		HLISTITEM sel = GetSelectedItem(), next = NULL;
		bool bDU = false;
		if(pMsg->wParam == VK_DOWN)
		{
			bDU = true;
			if(sel) 
				next = GetTrueNextItem(sel, true);
			else if(m_sbVert.IsWindowVisible() && (m_ei.m_curEdit == aplNone))
			{
				DoScroll(SB_LINEDOWN, 0, &m_sbVert, false);
				return 1;
			}
		}
		else if(pMsg->wParam == VK_UP)
		{
			bDU = true;
			if(sel) 
				next = GetTrueNextItem(sel, false);
			else if(m_sbVert.IsWindowVisible() && (m_ei.m_curEdit == aplNone))
			{
				DoScroll(SB_LINEUP, 0, &m_sbVert, false);
				return 1;
			}
		}
		if(next)
		{
			SelectItem(next);
			EnsureVisible(next);
		}
		if(sel && bDU) return 1;
		/*
		if(pMsg->wParam == VK_TAB)
		{
			AfxMessageBox(_T("tab!"));
			return 1;
		}
		*/
	}
	return CWnd::PreTranslateMessage(pMsg);
}

bool CaplExListCtrl::IsEditing()
{
	return (m_ei.m_curEdit != aplNone);
}
